package practice.book

import scala.concurrent.{ExecutionContext, Future}


/**
  * Created by lovepocky(lovepocky@foxmail.com) on 2015/11/4.
  */
object LearnningConcurrentProgrammingInScala {
	def main(args: Array[String]) {
		 
		
	}
	val isRunningExample_2 = false
	val isRunningExample_3 = false
	val isRunningExample_4 = false
	
	/**
	  * Chapter 2
	  */
	if (isRunningExample_2) {
		/** ex:p19 */
		def thread(body: => Unit): Thread = {
			val t = new Thread {
				override def run() = body
			}
			t.start()
			t
		}
		
		val t = thread {
			Thread.sleep(500)
			println("New Thread running.")
			Thread.sleep(500)
			println("Still running.")
			Thread.sleep(500)
			println("Completed.")
		}
		t.join()
		println("New Thread Joined")
		
	}
	
	/**
	  * Chapter 3
	  */
	if (isRunningExample_3) {
		import scala.concurrent._
		
		/*val executor = new ForkJoinPool
		executor.execute(new Runnable {
			def run(): Unit = {
				println("This task is run asynchronously")
			}
		})
		Thread.sleep(500)*/
		
		/*val pool = new ForkJoinPool(2)
		val ectx = ExecutionContext.fromExecutorService(pool)
		ectx.execute(new Runnable {
			override def run(): Unit = println("Running on the execution context")
		})
		Thread.sleep(500)*/
		
		def execute(body: => Unit) = ExecutionContext.global.execute(new Runnable {
			override def run(): Unit = body
		})
		
		//Running Test
		/*for (i <- 0 until 32) execute {
			Thread.sleep(2000)
			println(s"Task $i completed")
		}
		Thread.sleep(10000)*/
		
		/** ex:p52 */
		
		/*import java.util.concurrent.atomic._
		
		val uid = new AtomicLong(0L)
		def getUniqueId(): Long = uid.incrementAndGet()
		
		execute(println(s"Uid asynchronously: ${getUniqueId()}"))
		println(s"Got a uniqueId: ${getUniqueId()}")*/
		
		/** ex:p66 */
		
	}
	
	/**
	  * Chapter 4
	  */
	if (isRunningExample_4) {
		import ExecutionContext.Implicits.global
		import scala.io.Source
		
		/** ex:p88 */
		/*val BuildFile: Future[String] = Future {
			val f = Source.fromFile("build.sbt")
			try f.getLines.mkString("\n") finally f.close()
		}
		println(s"started reading the bulid file asynchronously")
		println(s"status: ${BuildFile.isCompleted}")
		Thread.sleep(250)
		println(s"status: ${BuildFile.isCompleted}")
		println(s"value: \n${BuildFile.value}")*/
		
		/** ex:p90 */
		/*def getUrlSpec(): Future[List[String]] = Future {
			val url = "http://www.w3.org/Addressing/URL/url-spec.txt"
			val url2 = "http://baike.baidu.com/link?url=Ik_Glbw2b8Fi8HVx1FGIelESobSViJMCXic0Ni2r8OmXzVMMvBo6hrO4iPK3hCM1VG7PYJ267fqCeipOCs5gEq"
			val f = Source.fromURL(url2)
			try f.getLines.toList finally f.close()
		}
		def find(lines: List[String], keyword: String): String = {
			lines.zipWithIndex collect {
				case (line, n) if line.contains(keyword) => (n, line)
			} mkString ("\n")
		}
		val urlSpec: Future[List[String]] = getUrlSpec()
		urlSpec foreach {
			case lines => println(find(lines, "telnet"))
		}
		urlSpec foreach {
			case lines => println(find(lines, "password"))
		}
		urlSpec.failed foreach {
			case t => println(s"exception occurred - $t")
		}
		
		import scala.util.{Failure, Success, Try}
		def handleMessage(t: Try[String]) = t match {
			case Success(msg) => println(msg)
			case Failure(error) => println(s"unexpected failure - $error")
		}
		println("callback registered, continuing with other work")
		Thread.sleep(2000)*/
		
		/** ex:p96 */
		import java.io._

		import org.apache.commons.io.FileUtils._

		import scala.collection.convert.decorateAsScala._
		
		def blacklistFile(name: String): Future[List[String]] = Future {
			val lines = Source.fromFile(name).getLines
			lines.filter(x => !x.startsWith("#") && !x.isEmpty).toList
		}
		def findFiles(patterns: List[String]): List[String] = {
			val root = new File(".")
			for {
				f <- iterateFiles(root, null, true).asScala.toList
				pat <- patterns
				abspat = root.getCanonicalPath + File.separator + pat.replaceFirst("/", "")
				if f.getCanonicalPath.contains(abspat)
			} yield f.getCanonicalPath
		}
		def blacklisted(name: String): Future[List[String]] = {
			blacklistFile(name).map(patterns => findFiles(patterns))
		}
		
		//		blacklistFile(".gitignore") foreach {
		//			case lines =>
		//				println(lines)
		//				val files = findFiles(lines)
		//				println(s"matches: ${files.mkString("\n")}")
		//		}
		
		//		val buildFile = Future {
		//			Source.fromFile("build.sbt").getLines
		//		} foreach {
		//			file => for (lines <- file) println(lines)
		//		}
		//		val longest = for (lines <- buildFile) yield lines.maxBy(lines => lines.length)
		//		longest foreach { case lines => println(s"longest line: $lines") }
		
		
		//		val netiquetteUrl = "http://www.ietf.org/rfc/rfc1855.txt"
		//		val netiquette = Future(Source.fromURL(netiquetteUrl).mkString)
		//		Future {Source.fromFile("build.sbt")} foreach(file => print(file.mkString))
		//		Source.fromURL(netiquetteUrl,"UTF-8").mkString foreach print
		
		/** ex: p104 (promise) */
		/*val p = Promise[String]
		val q = Promise[String]
		p.future foreach { case x => println(s"p succeeded with $x") }
		Thread.sleep(1000)
		p success ("assigned")
		q failure (new Exception("not kept"))
		q.future.failed foreach { case t => println(s"q failed with $t") }*/
		
		
		
		Thread.sleep(2000)
	}
	
	class ExerciseOfChapter1 {
		/** Ex:1 */
		def compose[A, B, C](g: B => C, f: A => B): A => C = {
			def h: A => C = ATypeVal => g(f(ATypeVal)) //todo Could 'ATypeVal' replaced with '_'?
			h
		}
		
		/*def fuse[A, B](a: Option[A], b: Option[B]): Option[(A, B)] = {
			val res: Option[(A, B)] = for ()
		}*/
		
	}
	
}

